home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / BOOTPDIP.C < prev    next >
C/C++ Source or Header  |  1997-09-07  |  31KB  |  1,003 lines

  1. /*
  2.  * Center for Information Technology Integration
  3.  *           The University of Michigan
  4.  *                    Ann Arbor
  5.  *
  6.  * Dedicated to the public domain.
  7.  * Send questions to info@citi.umich.edu
  8.  * BOOTP is documented in RFC 951 and RFC 1048
  9.  *
  10.  * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
  11.  */
  12.  
  13.  
  14.  
  15. /* Dynamic Ip Assignment for a Bootp Server
  16.  * Called when a client request is received and the bootp server doesnt' have a
  17.  * record for it.
  18.  *
  19.  * Design goals:
  20.  *   Assign an IP address
  21.  *   Separation/Identification of IP addresses assigned and not assigned
  22.  *   Time out mechanism to reclaim IP address
  23.  *    Timer, and arp on address with little activity
  24.  *   Reassignment to same machine if possible.
  25.  */     
  26. #include "global.h"
  27. #ifdef BOOTPSERVER
  28. #include <time.h>    
  29. #include "arp.h"
  30. #include "bootpd.h"
  31.  
  32.  
  33. #if !defined(_lint)
  34. static char rcsid[] OPTIONAL = "$Id: bootpdip.c,v 1.17 1997/09/07 21:18:28 root Exp root $";
  35. #endif
  36.  
  37. #define E_NOMEM 3101
  38. #define ERR_NOIPADDRESS    3103        /* No IP address available. */
  39.  
  40. #define THRESH_ON            20    /* (%) When to turn on reclaimation of IP addresses. */
  41. #define THRESH_CRITICAL       2    /* (#) */
  42. #define THRESH_OFF           50    /* (%) */
  43.  
  44. #define R_OFF                   0x01    /* Reclaimation is off. */
  45. #define R_RECLAIM               0x02    /* Reclaimation is on. */
  46. #define R_CRITICAL              0x04    /* Reclaimation is operating in critical state. */
  47. #define R_DONE                  0x08    /* Reclaimation is finishing up. */
  48. #define V_SWAIT                 0x10    /* Reclaimation is wait to start verif cycle. */
  49. #define V_VERIFY                0x20    /* Reclaimation is in verification cycle. */
  50.  
  51. #define TIME_RWAIT        (5)     /* Time between running reclm da_task */
  52. #define TIME_SWAIT              (30)    /* Time between cycles of starting address rec */
  53. #ifndef _lint
  54. #define TIME_VWAIT              (10)    /* Time to wait between sending ARPs to verify addresses. */
  55. #endif
  56. #define TIME_ADDRRETRY          (4 * 600) /* Time to wait before trying to reclaim an address. */
  57. #ifndef _lint
  58. #define TIME_ADDRRECLAIM        (900)   /* Time for which an address must be in the reclaimation */
  59. #endif
  60.                                         /* queue before being moved to the free list. */
  61.  
  62. #define RECLAIM_QUEUE_MAX       15      /* Maximum number of addresses in reclaimation queue. */
  63.  
  64.  
  65.  
  66. /*      dynamic_ip.c
  67.  *
  68.  * This file contains code to manage a range of dynamic IP addresses on a network.
  69.  */
  70.     
  71.  
  72.  
  73. /* Queue structures  */
  74.  
  75. struct  q_elt {
  76.         struct  q_elt *next;
  77. };
  78.  
  79. #define NULLQ_ELT (struct q_elt *) 0
  80.  
  81.  
  82. struct  q {
  83.         char *head;
  84.         char *tail;
  85. };
  86.  
  87. #ifndef _lint
  88. #define NULLQ_P (struct q *) 0
  89. #endif
  90.  
  91.  
  92. /* Dynamic IP structures */
  93.  
  94. struct daddr {
  95.         struct daddr    *da_next;       /* Queue link. */
  96.         uint32        da_addr;        /* IP address. */
  97.         time_t        da_time;        /* last time this address was answered for. */
  98.     char        da_hwaddr[1];   /* Hardware address, variable length. */
  99. };
  100.  
  101. #define NULLDADDR (struct daddr *) 0
  102.  
  103. struct drange_desc {
  104.         struct drange_desc *dr_next;    /* Queue link. */
  105.         struct iface    *dr_iface;      /* Pointer to network information. */
  106. #ifndef _lint
  107.     struct timer    timer;        /* Timer for reclaiming */
  108. #endif
  109.         uint32        dr_start;       /* First IP address in range. */
  110.         uint32        dr_end;         /* Last IP address in range. */
  111.         int16           dr_acount;      /* Number of IP addresses in range. */
  112.         int16           dr_fcount;      /* Number of IP addresses in free. */
  113.         int16           dr_rcount;      /* Number of IP addresses on reclmation queue  */
  114.         int16           dr_thon;        /* Threshold for turning on reclaimation. */
  115.         int16           dr_thcritical;  /* Threshold for critical reclaimation. */
  116.         int16           dr_thoff;       /* Threshold for turning off reclaimation. */
  117.         int32           dr_time_addrretry;      /* Time to wait before retrying addresses.
  118.                            Varies with state. */
  119.         int16           dr_hwaddrlen;   /* Length of hardware address. */
  120.         unsigned char   dr_rstate;      /* Reclaimation state. */
  121.         unsigned char   dr_vstate;      /* Verification state. */
  122.         time_t          dr_rtime;       /* Time stamp for reclaimation. */
  123.         struct daddr    *dr_raddr;      /* Address being verified. */
  124.         struct daddr    *dr_table;      /* Pointer to table of addresses. */
  125.         struct q        dr_usedq;       /* Pointer to list of used addresses. */
  126.         struct q        dr_reclaimq;    /* Pointer to list of addrs being reclaimed.  */
  127.         struct q        dr_freeq;       /* Pointer to list of free addresses. */
  128. };
  129.  
  130. #define NULLDRANGE (struct drange_desc *) 0
  131.  
  132.  
  133.  
  134.  
  135.  
  136. #define da_structlen(dr)        (sizeof (struct daddr) + dr->dr_hwaddrlen)
  137. #define da_getnext(dr,da)       ((struct daddr *) ((unsigned char *)da + da_structlen(dr)))
  138.  
  139.  
  140. /*
  141.  * Globals.
  142.  */
  143.  
  144. static int ifaceToArpMap[] = {
  145.         0,                                 /* CL_NONE */
  146.         ARP_ETHER,                             /* CL_ETHERNET */
  147.         ARP_PRONET,                             /* CL_PRONET_10 */
  148.         ARP_IEEE802,                            /* CL_IEEE8025 */
  149.         0,                                 /* CL_OMNINET */
  150.         ARP_APPLETALK,                          /* CL_APPLETALK */
  151.         0,                                   /* CL_SERIAL_LINE */
  152.         0,                                 /* CL_STARLAN */
  153.         ARP_ARCNET,                             /* CL_ARCNET */
  154.         ARP_AX25,                               /* CL_AX25 */
  155.         0,                                      /* CL_KISS */
  156.         0,                                      /* CL_IEEE8023 */
  157.         0,                                      /* CL_FDDI */
  158.         0,                                      /* CL_INTERNET_X25 */
  159.         0,                                      /* CL_LANSTAR */
  160.         0,                                      /* CL_SLFP */
  161.         ARP_NETROM,                             /* CL_NETROM */
  162.         0                                       /* NCLASS */
  163. };
  164.  
  165.  
  166.  
  167. static struct q                 rtabq;
  168. static struct timer        da_timer;
  169. char                bp_ascii[128];
  170.  
  171. static void da_runtask (void *arg);
  172. static struct q_elt *q_dequeue (struct q *queue);
  173. static void da_closeup (struct drange_desc *dr);
  174. static void dprint_addresses (struct drange_desc *dr);
  175. static int q_remove (struct q *source_queue,struct q_elt *qel);
  176. static void iptoa (uint32 ipaddr,char ipstr[16]);
  177. static void da_task (void);
  178. static int da_fill_reclaim (struct drange_desc *dr);
  179. static void da_do_verify (struct drange_desc *dr,int pendtime);
  180. static void da_enter_reclaim (struct drange_desc *dr);
  181. static void da_enter_done (struct drange_desc *dr);
  182. static void da_enter_off (struct drange_desc *dr);
  183. static void q_enqueue (struct q    *queue,struct q_elt *elem);
  184. static int da_get_old_addr (struct drange_desc *dr,char *hwaddr,struct daddr **dap);
  185. static int da_get_free_addr (struct drange_desc *dr,struct daddr **dap);
  186. static void da_enter_critical (struct drange_desc *dr);
  187. static void q_init (struct q *queue);
  188.  
  189.  
  190.  
  191. /*
  192.  * Shutdown routines.
  193.  */
  194.  
  195. /*
  196.  * Done serving a network.
  197.  */
  198. int
  199. da_done_net (struct iface *iface)
  200. {
  201.         struct drange_desc *dr;
  202.  
  203.         /* Find the network table */
  204.         for(dr = (struct drange_desc *) rtabq.head; dr != NULLDRANGE; dr = dr->dr_next){
  205.                 if(iface == dr->dr_iface)
  206.                         break;
  207.         }
  208.  
  209.         if(dr == NULLDRANGE){
  210.         bp_log("Range for interface '%s' not found.\n", iface->name);
  211.         return -1;
  212.     }
  213.  
  214.         da_closeup(dr);
  215.     bp_log("Range removed for iface %s\n", iface->name);
  216.         return 0;
  217. }
  218.  
  219.  
  220.  
  221.  
  222. /*
  223.  * Print the status of the da structures.
  224.  */
  225. void
  226. da_status (struct iface *iface)
  227. {
  228.         struct drange_desc *dr;
  229.  
  230.     /* If no interface was specified, print all the range information */
  231.     if(iface == NULLIF){
  232.             for(dr = (struct drange_desc *) rtabq.head; dr != NULLDRANGE; 
  233.          dr = dr->dr_next) 
  234.             dprint_addresses(dr);
  235.     
  236.     } else {
  237.         /* Print the specified range's information */
  238.         /* Find the specified interface */
  239.             for(dr = (struct drange_desc *) rtabq.head; 
  240.          (dr != NULLDRANGE) && (dr->dr_iface != iface); 
  241.          dr = dr->dr_next)
  242.             ; 
  243.         
  244.         /* If network not found, return */
  245.         if(dr == NULLDRANGE){
  246.             tprintf("Range for interface '%s' not found.\n", iface->name);
  247.             return;    
  248.         }
  249.         /* The range has been found.  Print it. */
  250.         dprint_addresses(dr);
  251.     }
  252. }
  253.  
  254.  
  255.  
  256. /*
  257.  * Finish up service.  Close up on each of the address ranges.
  258.  */
  259. void
  260. da_shut()
  261. {
  262.         struct drange_desc *dr;
  263.  
  264.     stop_timer(&da_timer);
  265.         while((dr = (struct drange_desc *)q_dequeue (&rtabq)) != NULLDRANGE)
  266.                 da_closeup(dr);
  267. }
  268.  
  269.  
  270. /*
  271.  * Release resource for a network.
  272.  */
  273. static void
  274. da_closeup (struct drange_desc *dr)
  275. {
  276.         free(dr->dr_table);                /* Free the address table. */
  277.         (void) q_remove(&rtabq, (struct q_elt *)dr);    /* Dequeue the range descriptor. */
  278.         free(dr);                    /* Free the range descriptor. */
  279. }
  280.  
  281.  
  282.  
  283. /* This is only called from a command */
  284. static void
  285. dprint_addresses (struct drange_desc *dr)
  286. {
  287.         struct daddr *da;
  288.         char ipa[16];
  289.     char ipb[16];
  290.     struct arp_type    *at;
  291.     
  292.     at = &Arp_type[dr->dr_iface->type];
  293.  
  294.     iptoa(dr->dr_start, ipa);
  295.     iptoa(dr->dr_end, ipb);
  296.     tprintf("Interface %s range: %s - %s\n", dr->dr_iface->name, ipa, ipb);
  297.  
  298.         da = (struct daddr *) dr->dr_freeq.head;
  299.     tputs("Free address queue\n");
  300.         while(da){
  301.                 iptoa(da->da_addr, ipa);
  302.                 tprintf("    %s  last used by %s\n", ipa,(*at->format)(bp_ascii, da->da_hwaddr));
  303.                 da = da->da_next;
  304.         }
  305.  
  306.         da = (struct daddr *) dr->dr_usedq.head;
  307.         tputs("\nUsed address queue\n");
  308.         while(da){
  309.                 iptoa(da->da_addr, ipa);
  310.                 tprintf("    %s  in use by %s\n", ipa, (*at->format)(bp_ascii, da->da_hwaddr));
  311.                 da = da->da_next;
  312.         }
  313.  
  314.         da =(struct daddr *) dr->dr_reclaimq.head;
  315.         tputs("\nReclaimation address queue\n");
  316.         while(da){
  317.                 iptoa(da->da_addr, ipa);
  318.                 tprintf("    %s  in use by %s?\n", ipa, (*at->format)(bp_ascii, da->da_hwaddr));
  319.                 da = da->da_next;
  320.         }
  321.         tputc('\n');
  322. }
  323.  
  324.  
  325.  
  326. /*
  327.  * Reclaimation routines.
  328.  */
  329. static void
  330. da_runtask (void *p OPTIONAL)
  331. {
  332.     stop_timer(&da_timer);
  333.     da_task();
  334.     set_timer(&da_timer,TIME_RWAIT*1000L);
  335.     start_detached_timer(&da_timer);
  336. }
  337.  
  338. /*
  339.  * Called periodically to run reclaimation.
  340.  */
  341. static void
  342. da_task()
  343. {
  344.     struct drange_desc *dr;
  345.     time_t now;
  346.     int arpHardware, arpPendtime;
  347.  
  348.     now = time(NULL);
  349.  
  350.     for(dr = (struct drange_desc *)rtabq.head; dr != NULLDRANGE; dr = dr->dr_next){
  351.  
  352.         arpHardware = ifaceToArpMap [dr->dr_iface->type];
  353.         arpPendtime = Arp_type[arpHardware].pendtime;
  354.  
  355.         if(!(dr->dr_rstate & R_OFF)){    /* If doing reclaimation on this range. */
  356.             if(dr->dr_vstate == V_SWAIT){    /* If in wait sub-state. */
  357.                 /* Doing reclaimation on this range and am waiting to 
  358.                  * start a cycle of address
  359.                  * verification.  Check if it is time to start the 
  360.                  * cycle. */
  361.  
  362.                 if(now - dr->dr_rtime > TIME_SWAIT){
  363.                     /* Start the cycle.  */
  364.                     if(!(dr->dr_rstate & R_DONE))
  365.                         (void) da_fill_reclaim(dr);
  366.  
  367.                     dr->dr_vstate = V_VERIFY; /* verify sub-state. */
  368.                     dr->dr_raddr = NULLDADDR; /* start at beginning */
  369.                 }
  370.             }
  371.             /* If in the verify state (may have just been changed above), and 
  372.              * enough time has passed since last lookup, check it and start
  373.              * the next lookup. */
  374.  
  375.             if(dr->dr_vstate == V_VERIFY){
  376.                 if(now - dr->dr_rtime > (time_t) arpPendtime){
  377.                     da_do_verify(dr, arpPendtime); /* Verify address. */
  378.                     dr->dr_rtime = time(NULL); /* Set time stamp. */
  379.                     if(dr->dr_raddr == NULLDADDR){ /* If at end... */
  380.                         dr->dr_vstate = V_SWAIT; /* Q empty; enter wait sub-state. */
  381.                     }
  382.                 }
  383.             }
  384.             
  385.             /* 
  386.              * State transitions.  May have moved some addresses to free list.
  387.              * If so, I may be able to move to a "lower" state.
  388.              */
  389.             switch(dr->dr_rstate){
  390.             /* case R_OFF: Not handled. */
  391.             case R_CRITICAL:
  392.                 /* Have conditions droped below critical threshhold? */
  393.                 if(dr->dr_fcount > dr->dr_thcritical)    
  394.                     da_enter_reclaim(dr);
  395.                 /* Fall through. */
  396.             case R_RECLAIM:
  397.                 /* Have I reclaimed enough addresses? */
  398.                 if(dr->dr_fcount > dr->dr_thoff)    
  399.                     da_enter_done(dr);
  400.                 /* Fall through. */
  401.             case R_DONE:
  402.                 /* Am I in the done state and have exausted the reclaimation queue? */
  403.                 if((dr->dr_rstate & R_DONE) && dr->dr_reclaimq.head == NULLCHAR) 
  404.                     da_enter_off(dr);
  405.                 break;
  406.             default:
  407.                 break;
  408.             }
  409.         }
  410.     }
  411. }
  412.  
  413.  
  414.  
  415.  
  416. /* 
  417.  * Enter the DONE state.  Can't get to the done state from the off state.
  418.  */
  419. static void
  420. da_enter_done (struct drange_desc *dr)
  421. {
  422.     char ipa[16], ipb[16];
  423.     
  424.     iptoa(dr->dr_start, ipa);
  425.     iptoa(dr->dr_end, ipb);
  426.  
  427.     if((dr->dr_rstate & R_OFF) == 0){ 
  428.         dr->dr_rstate = R_DONE;
  429.         dr->dr_time_addrretry = TIME_ADDRRETRY;        /* Wait a while before retrying addresses. */
  430.     }
  431. }
  432.  
  433.  
  434. /* 
  435.  * Enter the OFF state.
  436.  */
  437. static void
  438. da_enter_off (struct drange_desc *dr)
  439. {
  440.     char ipa[16], ipb[16];
  441.     
  442.     iptoa(dr->dr_start, ipa);
  443.     iptoa(dr->dr_end, ipb);
  444.  
  445.     dr->dr_rstate = R_OFF;
  446. }
  447.  
  448.  
  449. /*
  450.  * Verify addresses.
  451.  * To avoid flodding the network and our address resolution queue I only send
  452.  * out one ARP at a time.  This routine is called periodically to step through
  453.  * the reclaimation queue.  The first step is to check for a responce to the
  454.  * ARP that was sent out previously.  If there is a responce I move the address
  455.  * to the used queue. The next step is to send out an ARP for the next address
  456.  * on the recliamation queue. After a suitable intervel (TIME_VTIME) I'll be
  457.  * called again.
  458.  */
  459. static void
  460. da_do_verify (struct drange_desc *dr, int pendtime)
  461. {
  462.     struct daddr *da, *dn;
  463.     struct iface *iface;
  464.     time_t now;
  465.     struct arp_tab *ap;
  466.     int16 arpType;
  467.     
  468.      now = time((time_t *)0);
  469.      iface = dr->dr_iface;
  470.     arpType = (int16) ifaceToArpMap[iface->type];
  471.  
  472.     /*
  473.       * If I sent an ARP for an address, check if that ARP has been responded to.
  474.      * If dr_raddr points to an address record, I have previously sent an
  475.      * ARP for that address.  Check the ARP cache for a responce.
  476.      * If dr_raddr is NULL then I am to start at the head of the reclaim queue.
  477.       */
  478.  
  479.     if(dr->dr_raddr != NULLDADDR){
  480.         /* ARP has been sent for dr_raddr.  Check the ARP cache for a responce. */
  481.         da = dr->dr_raddr;
  482.         dn = da->da_next;
  483.  
  484.         ap = arp_lookup(arpType, (uint32) da->da_addr, iface);
  485.  
  486.         if((ap != NULLARP) && (ap->state == ARP_VALID)){
  487.             /* Host responded to arp.  Place address on used queue.
  488.              * Copy in physical address of host using address to
  489.              * make sure our info is up to date.  
  490.              * I could verify that physical address of host
  491.              * responding to  ARP matches the physical address of
  492.              * the host I think owns the address.  If don't match
  493.              * someone is probably using an incorrect address.
  494.              */
  495.  
  496.             (void) q_remove(&dr->dr_reclaimq, (struct q_elt *)da);
  497.             --dr->dr_rcount;
  498.             da->da_time = now;        /* Time tested. */
  499.             memcpy(da->da_hwaddr, ap->hw_addr, (size_t)Arp_type[ap->hardware].hwalen);
  500.             q_enqueue(&dr->dr_usedq, (struct q_elt *)da);
  501.  
  502.         } else {
  503.             /* Host did not respond to ARP.  If addr on reclaim
  504.              * queue long enough, move it to the free queue.
  505.              */
  506.             if(now - da->da_time >= (time_t) pendtime){
  507.                 (void) q_remove(&dr->dr_reclaimq, (struct q_elt *)da);
  508.                 --dr->dr_rcount;
  509.                 q_enqueue(&dr->dr_freeq,(struct q_elt *)da);
  510.                 ++dr->dr_fcount;
  511.                 bp_log("Reclaimed address %s on net %s.\n", 
  512.                     inet_ntoa(da->da_addr), dr->dr_iface->name);
  513.             }
  514.         }
  515.     } else {
  516.         /* Use first addr in reclaimq. */
  517.         dn = (struct daddr *) dr->dr_reclaimq.head;
  518.     }
  519.     /*
  520.       * Now move to the next entry in the queue and ARP for it.
  521.       */
  522.      da = dn;
  523.     if(da != NULLDADDR){
  524.         ap = arp_lookup(arpType, da->da_addr, iface);
  525.         if(ap != NULLARP) arp_drop(ap);
  526.         (void) res_arp(iface, arpType, da->da_addr, NULLBUF);
  527.     }
  528.     dr->dr_raddr = da;    /* Verify this address next time around. */
  529.     dr->dr_rtime = time(NULL);
  530. }
  531.  
  532.  
  533. /*
  534.  * Fill the reclaimation list from the used list.  Take addresses off the head
  535.  * of the used queue until the reclaim queue is full, the used queue is empty,
  536.  * or the address at the head of the used queue has been verified (responded
  537.  * to an ARP) within dr_time_addrretry tocks.
  538.  */
  539. static int
  540. da_fill_reclaim (struct drange_desc *dr)
  541. {
  542.         struct daddr *da;
  543.         time_t now;
  544.  
  545.         now = time((time_t *)0);
  546.  
  547.         while(dr->dr_rcount < RECLAIM_QUEUE_MAX){
  548.         /* Look at first address on used queue. */
  549.                 da = (struct daddr *) dr->dr_usedq.head;
  550.                 if(da == NULLDADDR)
  551.             return 0;    /* If used queue is empty, done filling. */
  552.                 if(now - da->da_time < (time_t) dr->dr_time_addrretry)
  553.                         return 0;
  554.  
  555.         /* If the first element has responded to in ARP recently.
  556.          * I am done filling.
  557.          */
  558.         /* Get first address on used queue. */
  559.                 da = (struct daddr *) q_dequeue(&dr->dr_usedq);
  560.         /* Mark time addr put in reclaim queue. */
  561.                 da->da_time = now;
  562.         /* Put it at end of reclaim queue. */
  563.                 q_enqueue(&dr->dr_reclaimq,(struct q_elt *)da);
  564.                 ++dr->dr_rcount;
  565.         }
  566.         return 0;
  567. }
  568.  
  569.  
  570. /*
  571.  * Address assignment routines.
  572.  */
  573.  
  574. /*
  575.  * Assign an address.
  576.  */
  577. int
  578. da_assign (
  579. struct iface *iface,    /* -> Pointer to lnet struct of net on which to assign addr. */
  580. char    *hwaddr,    /* -> Pointer to hardware address of hosts. */
  581. uint32    *ipaddr        /* <- Address assigned to host. */
  582. ) {
  583.     struct drange_desc *dr;    
  584.     struct daddr *da;    
  585.     int status;
  586.     struct arp_type    *at;
  587.  
  588.     /* Find the network table */
  589.     for(dr = (struct drange_desc *) rtabq.head; dr != NULLDRANGE; dr = dr->dr_next){
  590.         if(iface == dr->dr_iface)
  591.             break;    
  592.     }
  593.  
  594.     if(dr == NULLDRANGE){
  595.         *ipaddr = 0;
  596.         return ERR_NOIPADDRESS;
  597.     }
  598.  
  599.     /* If this host had an address assigned previously, try to reassign
  600.      * that. If no previous address, assign a new one.
  601.      */
  602.     status = da_get_old_addr(dr, hwaddr, &da);
  603.     if(status != 0) 
  604.         status = da_get_free_addr(dr, &da);
  605.     
  606.     /* If I got an address, assign it and link it in to the use list. */
  607.     if(status == 0){
  608.         memcpy(da->da_hwaddr, hwaddr, (size_t)dr->dr_hwaddrlen);
  609.         *ipaddr = da->da_addr;
  610.         da->da_time = time(NULL);    /* Time assigned */
  611.         q_enqueue(&dr->dr_usedq,(struct q_elt *)da);
  612.         at = &Arp_type[dr->dr_iface->type];
  613.         bp_log("IP addr %s assigned to %s on network %s\n",
  614.          inet_ntoa(*ipaddr),
  615.          (*at->format)(bp_ascii, hwaddr), dr->dr_iface->name);
  616.     }
  617.  
  618.         switch(dr->dr_rstate){
  619.         case R_OFF:
  620.         case R_DONE:
  621.                 if(dr->dr_fcount <= dr->dr_thon) 
  622.             da_enter_reclaim(dr);
  623.                 /* Fall through. */
  624.         case R_RECLAIM:
  625.                 if(dr->dr_fcount <= dr->dr_thcritical) 
  626.             da_enter_critical(dr);
  627.                 break;
  628.         /* case R_CRITICAL: is not handled. */
  629.         default:
  630.             break;
  631.         }
  632.         return status;
  633. }
  634.  
  635.  
  636. /*
  637.  * Enter the reclaimation state.
  638.  */
  639. static void
  640. da_enter_reclaim (struct drange_desc *dr)
  641. {
  642.         char ipa[16], ipb[16];
  643.  
  644.         iptoa(dr->dr_start, ipa);
  645.         iptoa(dr->dr_end, ipb);
  646.  
  647.         if(dr->dr_rstate & R_OFF){
  648.                 dr->dr_vstate = V_SWAIT;  /* da_enter_reclaim: R_OFF */
  649.                 dr->dr_rtime = 0;
  650.         }
  651.         dr->dr_rstate = R_RECLAIM;
  652.         dr->dr_time_addrretry = TIME_ADDRRETRY;         /* Wait a while before retrying addresses. */
  653. }
  654.  
  655. /*
  656.  * Search for hwaddr on the used list, the reclaimation list, and the free list.
  657.  */
  658. static int
  659. da_get_free_addr (struct drange_desc *dr, struct daddr **dap)
  660. {
  661.         *dap = (struct daddr *) q_dequeue(&(dr->dr_freeq));
  662.         if(*dap == NULLDADDR) 
  663.         return ERR_NOIPADDRESS;
  664.         --dr->dr_fcount;
  665.  
  666.         return 0;
  667. }
  668.  
  669. /*
  670.  * Search for hwaddr on the used list, the reclaimation list, and the free list.
  671.  */
  672. static int
  673. da_get_old_addr (struct drange_desc *dr, char *hwaddr, struct daddr **dap)
  674. {
  675.         struct daddr *da;
  676.  
  677.     /* Search the used queue */
  678.         for(da = (struct daddr *) dr->dr_usedq.head; da != NULLDADDR; da = da->da_next){
  679.                 if(memcmp(da->da_hwaddr, hwaddr, (size_t)dr->dr_hwaddrlen) == 0){
  680.                         (void) q_remove(&dr->dr_usedq,(struct q_elt *)da);
  681.                         *dap = da;
  682.                         return 0;
  683.                 }
  684.         }
  685.  
  686.     /* Search the relaimq queue */
  687.         for(da = (struct daddr *) dr->dr_reclaimq.head; da != NULLDADDR; 
  688.         da = da->da_next){
  689.                 if(memcmp(da->da_hwaddr, hwaddr, (size_t)dr->dr_hwaddrlen) == 0){
  690.                         /* Here is the address.  I have to be carefull in removing it from
  691.              * reclaim queue, I may be verifying this address.
  692.                          * If I am, I have to fix up the pointers before removing this
  693.                          * element.
  694.                          */
  695.                         if((dr->dr_rstate & R_OFF) == 0 && dr->dr_vstate == V_VERIFY 
  696.                 && dr->dr_raddr == da){ 
  697.                 /* I am verifying this very address.  */
  698.                                 /* Start over.  
  699.                  * This should happen very infrequently at most. */
  700.                                 dr->dr_vstate = V_SWAIT;  /* get_old_addr */
  701.                         }
  702.                         (void) q_remove(&dr->dr_reclaimq,(struct q_elt *)da);
  703.                         *dap = da;
  704.                         return 0;
  705.                 }
  706.         }
  707.  
  708.     /* Search the free queue */
  709.         for(da = (struct daddr *) dr->dr_freeq.head; da != NULLDADDR; da = da->da_next){
  710.                 if(memcmp(da->da_hwaddr, hwaddr, (size_t)dr->dr_hwaddrlen) == 0){
  711.                         (void) q_remove(&dr->dr_freeq,(struct q_elt *)da);
  712.                         --dr->dr_fcount;
  713.                         *dap = da;
  714.                         return 0;
  715.                 }
  716.         }
  717.         return ERR_NOIPADDRESS;
  718. }
  719.  
  720. #ifdef    notdef
  721. static void
  722. dprint_dr_record (struct drange_desc *dr)
  723. {
  724.         bp_log("Queue link   x%lx\n", dr->dr_next);
  725.         bp_log("Pointer to network information         x%lx\n", dr->dr_iface);
  726.         bp_log("First IP address in range              x%lx\n", dr->dr_start);
  727.         bp_log("Last IP address in range               x%lx\n", dr->dr_end);
  728.         bp_log("Number of IP addresses in range        %d\n", dr->dr_acount);
  729.         bp_log("Number of IP addresses in free         %d\n", dr->dr_fcount);
  730.         bp_log("Number of IP addresses on reclaimation queue %d\n", 
  731.         dr->dr_rcount);
  732.         bp_log("Threshold for turning on reclaimation  %d\n", dr->dr_thon);
  733.         bp_log("Threshold for critical reclaimation    %d\n", dr->dr_thcritical);
  734.         bp_log("Threshold for turning off reclaimation %d\n", dr->dr_thoff);
  735.         bp_log("Time to wait before retrying addresses %ld\n", 
  736.         dr->dr_time_addrretry);
  737.         bp_log("Length of hardware address             %d\n", dr->dr_hwaddrlen);
  738.         bp_log("Reclaimation state                     %d\n",(int)dr->dr_rstate);
  739.         bp_log("Verification state                     %d\n",(int)dr->dr_vstate);
  740.         bp_log("Time stamp for reclaimation            %ld\n", dr->dr_rtime);
  741.         bp_log("Address being verified                 x%lx\n", dr->dr_raddr);
  742.         bp_log("Pointer to table of addresses          x%lx\n", dr->dr_table);
  743.         bp_log("uesdq x%lx  reclaimq                   x%lx  freeq x%lx\n", dr->dr_usedq, 
  744.         dr->dr_reclaimq, dr->dr_freeq);
  745. }
  746. #endif
  747.  
  748.  
  749. /*
  750.  * Enter the critical reclaimation state.
  751.  */
  752. static void
  753. da_enter_critical (struct drange_desc *dr)
  754. {
  755.         char ipa[16], ipb[16];
  756.     char *ipc;
  757.  
  758.     ipc = inet_ntoa(dr->dr_start);
  759.     strcpy(ipa, ipc);
  760.     ipc = inet_ntoa(dr->dr_end);
  761.     strcpy(ipb, ipc);
  762.  
  763.         if((dr->dr_rstate & R_OFF) == 0){
  764.                 dr->dr_vstate = V_SWAIT;    /* Enter critical, & R_OFF */
  765.                 dr->dr_rtime = 0;
  766.         }
  767.         dr->dr_rstate = R_CRITICAL;
  768.         dr->dr_time_addrretry = 0;      /* Retry addresses as fast as possible. */
  769. }
  770.  
  771. /*
  772.  * Initialization    
  773.  */
  774. /*
  775.  * Initialize the Dynamic address assignment module.
  776.  */
  777. int
  778. da_init()
  779. {
  780.         q_init(&rtabq);
  781.         return 0;
  782. }
  783.  
  784. /*
  785.  * Begin dynamic address service for a network.
  786.  */
  787. int
  788. da_serve_net (
  789. struct iface *iface,        /* Pointer to lnet record. */
  790. uint32 rstart,            /* First address in range. */
  791. uint32 rend            /* Last address in range. */
  792. ) {
  793.     struct drange_desc *dr;    /* Pointer to the range descriptor. */
  794.     struct daddr *da;    /* Pointer to an address structure. */
  795.     int32 rcount;        /* Number of addresses range. */
  796.     time_t now;        /* Current time. */
  797.     int16 i;
  798.     char ipc[16], ipd[16];
  799.  
  800.         /* Find the network table */
  801.         for(dr = (struct drange_desc *) rtabq.head; dr != NULLDRANGE;
  802.      dr = dr->dr_next){
  803.                 if(iface == dr->dr_iface)
  804.                         break;
  805.         }
  806.  
  807.     
  808.     if(dr == NULLDRANGE){
  809.         /* If there is no network table, allocate a new one
  810.          *
  811.           * Allocate the memory I need.
  812.           */
  813.         dr = (struct drange_desc *) callocw(1, sizeof(*dr));
  814.         if(dr == NULLDRANGE) 
  815.             return E_NOMEM;
  816.     } else if((dr->dr_start != rstart) || (dr->dr_end != rend)) 
  817.         /* If the range is different, create a new range */
  818.         free(dr->dr_table);
  819.     else
  820.         return 0; /* There is no change, return */
  821.  
  822.  
  823.     rcount = (long) ((rend - rstart) + 1);
  824.     da = (struct daddr *) callocw(1,(sizeof (*da) + (uint32) iface->iftype->hwalen) * (uint32) rcount);
  825.     if(da == NULLDADDR) 
  826.         return E_NOMEM;
  827.  
  828.     /* 
  829.      * Got the memory, fill in the structures.
  830.      */
  831.     dr->dr_iface = iface;
  832.     dr->dr_start = rstart;
  833.     dr->dr_end = rend;
  834.     dr->dr_acount = (int16) rcount;
  835.     dr->dr_fcount = 0;
  836.     dr->dr_rcount = 0;
  837.     dr->dr_thon = (int16) ((rcount * THRESH_ON) / 100);
  838.     dr->dr_thcritical = THRESH_CRITICAL;
  839.     dr->dr_thoff = (int16) ((rcount * THRESH_OFF) / 100);
  840.     dr->dr_time_addrretry = 0;
  841.         dr->dr_hwaddrlen = (int16) iface->iftype->hwalen;
  842.     dr->dr_rstate = R_OFF;
  843.     dr->dr_vstate = V_SWAIT;            /* Initialize */
  844.     dr->dr_rtime = 0;
  845.     dr->dr_raddr = NULLDADDR;
  846.     dr->dr_table = da;
  847.  
  848.     /* 
  849.      * Fill in the table and link them all onto the used list.
  850.      */
  851.     (void) time(&now);
  852.     for(i = 0, da = dr->dr_table; i < dr->dr_acount; ++i, da = da_getnext(dr, da)){
  853.         da->da_addr = rstart++;
  854.         da->da_time = 0;        /* Initiallize at 0, only here */
  855.         q_enqueue(&dr->dr_usedq,(struct q_elt *)da);
  856.     }
  857.     /* and set up the timer stuff */
  858.     if(rtabq.head == NULLCHAR){
  859.         set_timer(&da_timer,TIME_RWAIT*1000L);
  860.                da_timer.func = da_runtask;
  861.                da_timer.arg = (void *) 0;
  862.         start_detached_timer(&da_timer);
  863.     }
  864.     q_enqueue(&rtabq,(struct q_elt *)dr);
  865.     da_enter_critical(dr);    /* Start reclaiming some of these addresses. */
  866.  
  867.     iptoa(dr->dr_start, ipc);
  868.     iptoa(dr->dr_end, ipd);
  869.     bp_log("DynamicIP range: %s - %s\n", ipc, ipd);
  870.     return 0;
  871. }
  872.  
  873.  
  874. /*
  875.  * Routines to implement a simple forward linked queue.
  876.  */
  877.  
  878. /*
  879.  *      q_init()
  880.  *      Initialize simple Q descriptor
  881.  */
  882. static void
  883. q_init (struct q *queue)
  884. {
  885.         queue->head = 0;
  886.         queue->tail = 0;
  887. }
  888.  
  889.  
  890. /*
  891.  *      q_enqueue()
  892.  *              Enqueue an element in a simple Q.
  893.  */
  894. void
  895. q_enqueue (struct q *queue, struct q_elt *elem)
  896. {
  897.         struct q_elt *last;
  898.  
  899.         if(queue->tail != NULLCHAR){  /* If not empty Q... */
  900.                 last = (struct q_elt *) queue->tail;
  901.                 last->next = elem;
  902.         }
  903.         else
  904.         queue->head = (char *) elem;
  905.  
  906.         queue->tail = (char *) elem;
  907.         elem->next = NULLQ_ELT;
  908. }
  909.  
  910.  
  911. /*
  912.  *      q_dequeue       ()
  913.  *      Pull an element off of the head of a Q.
  914.  */
  915. static struct q_elt *
  916. q_dequeue (struct q *queue)
  917. {
  918.         struct q_elt *elem;
  919.  
  920.         if(queue->head == NULLCHAR)
  921.         return NULLQ_ELT; /* return NULL when empty Q */
  922.         elem = (struct q_elt *) queue->head;
  923.         queue->head = (char *) elem->next;
  924.         elem->next = NULLQ_ELT;
  925.         if(queue->head == NULLCHAR)
  926.         queue->tail = NULLCHAR;
  927.         return elem;
  928. }
  929.  
  930.  
  931. /*
  932.  *      Remove an element from the middle of a queue.  Note that
  933.  *      there is no mutex here, so this shouldn't be used on
  934.  *      critical Qs
  935.  */
  936.  
  937. static int
  938. q_remove (struct q *source_queue, struct q_elt *qel)
  939. {
  940.         struct q_elt *prev, *e;
  941.  
  942.         /*   Case : removing first in Q */
  943.  
  944.         if(qel == (struct q_elt *) source_queue->head){
  945.                 source_queue->head = (char *)qel->next;  /* trying to remove first in queue... */
  946.                 if(source_queue->head == NULLCHAR)      /* nothing left... */
  947.                         source_queue->tail = NULLCHAR;     /* blank out the Q */
  948.                 else if(source_queue->head == source_queue->tail){ /* One thing left */
  949.                         e = (struct q_elt *) source_queue->head; /* As insurance, set it's next to NULL. */
  950.                         e->next = NULLQ_ELT;
  951.                 }
  952.                 return 0;
  953.         }
  954.  
  955.         /* find Q element before qel, so that we can link around qel */
  956.         for(prev = (struct q_elt *) source_queue->head; prev->next != qel; prev = prev->next)
  957.                 if(prev == NULLQ_ELT)
  958.                         return 1;
  959.  
  960.         /* Case : Removing last in Q */
  961.  
  962.         if(qel == (struct q_elt *) source_queue->tail){     /* trying to remove last one in queue... */
  963.                 prev->next = NULLQ_ELT;   /* there is a prev elt, since we return on first */
  964.                 source_queue->tail = (char *) prev;
  965.                 return 0;
  966.         }
  967.  
  968.         /*  else, removing a queue element in the middle...  */
  969.         prev->next = qel->next;
  970.         return 0;
  971. }
  972.  
  973. /*
  974.  * Support Routines
  975.  */
  976.  
  977. static void
  978. iptoa (uint32 ipaddr, char ipstr[16])
  979. {
  980.     char *tmpStr;
  981.  
  982.     tmpStr = inet_ntoa(ipaddr);
  983.     strcpy(ipstr, tmpStr);
  984. }
  985.  
  986.  
  987. #ifdef    notdef
  988. static  void
  989. build_hex_string (char *fromstr, int  len, char *tostr)
  990. {
  991.     int i;
  992.  
  993.     for(i=0; i < len; i++){
  994.         sprintf(tostr, "%02x", fromstr[i]);
  995.         tostr++;
  996.         tostr++;
  997.     }
  998.     fromstr[len] = 0;
  999. }
  1000. #endif
  1001.  
  1002. #endif    /* BOOTPSERVER */
  1003.